package com.liuche.pictureserver.aop;

import com.liuche.pictureserver.aop.annotation.Mask;
import com.liuche.pictureserver.aop.annotation.MaskedField;
import com.liuche.pictureserver.common.exception.BizException;
import com.liuche.pictureserver.enums.UserRoleEnum;
import com.liuche.pictureserver.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 方法返回值脱敏
 *
 * @author liuche
 */
@Slf4j
@Aspect
@Component
public class MaskInterceptor {
    // 之前反射过的类的信息
    private static final Map<Class<?>, Field[]> CLASS_MAP = new HashMap<>();

    /**
     * 执行拦截，处理带有 @MaskReturnValue 注解的方法
     *
     * @param joinPoint 切入点
     * @param mask      脱敏注解
     */
    @Around("@annotation(mask)")
    public Object doInterceptor(ProceedingJoinPoint joinPoint, Mask mask) throws Throwable {
        // 获取方法的返回值
        Object result = joinPoint.proceed();

        // 如果返回值是对象，则执行字段脱敏
        if (result != null) {
            maskFields(result);
        }

        return result;
    }

    /**
     * 遍历对象的字段，处理带有 @MaskedField 注解的字段
     *
     * @param object 被处理的对象
     */
    private void maskFields(Object object) {
        // 校验权限
        if (!authUser()) {
            return;
        }

        Class<?> clazz = object.getClass();
        // 得到属性字段
        Field[] fields = CLASS_MAP.computeIfAbsent(clazz, k -> clazz.getDeclaredFields());

        // 获取类中的所有字段
        for (Field field : fields) {
            if (field.isAnnotationPresent(MaskedField.class)) {
                try {
                    Object fieldValue = getFieldValue(field, object);
                    // 处理集合字段
                    if (fieldValue instanceof Iterable) {
                        for (Object item : (Iterable<?>) fieldValue) {
                            maskFields(item);
                        }
                    } else if (ObjectUtils.isNotEmpty(fieldValue)) {
                        setFieldValue(field, object, null);
                    }

                } catch (IllegalAccessException e) {
                    log.error("value reflect error", e);
                    throw new BizException(500, "value reflect error");
                }
            }
        }
    }

    /**
     * 校验是否是需要脱敏
     *
     * @return 结果
     */
    private boolean authUser() {
        return ObjectUtils.isEmpty(UserHolder.getUserInfo()) || !UserHolder.getUserRole().equals(UserRoleEnum.ADMIN.getValue());
    }

    /**
     * 获取字段值
     *
     * @param field  字段
     * @param object 对象
     * @return 字段值
     * @throws IllegalAccessException 异常
     */
    private Object getFieldValue(Field field, Object object) throws IllegalAccessException {
        try {
            return field.get(object);
        } catch (IllegalAccessException e) {
            // 尝试通过反射获取私有字段的值
            field.setAccessible(true);
            return field.get(object);
        }
    }

    /**
     * 设置字段值
     *
     * @param field  字段
     * @param object 对象
     * @param value  值
     * @throws IllegalAccessException 异常
     */
    private void setFieldValue(Field field, Object object, Object value) throws IllegalAccessException {
        try {
            field.set(object, value);
        } catch (IllegalAccessException e) {
            // 尝试通过反射设置私有字段的值
            field.setAccessible(true);
            field.set(object, value);
        }
    }
}
